/*
*
==============================================================================
*  Name        : 
*  Part of     : Omen Game Engine
*  Description : 
*  Version     : 1.0
*
*  Copyright (c) 2013 Lauri Kortevaara.
* 
==============================================================================
*/

#pragma once

/// Omen Headers
#include "OmenConfig.h"
#include "IOmenObject.h"
#include "IOmenRenderable.h"
#include "IOmenShader.h"
#include "IOmenTexture.h"
#include "IOmenMaterial.h"

#include "OmenMath.h"

/// STL Headers
#include <vector>

namespace Omen
{
 
    class IModel;

    class OMEN_API IMesh : public Omen::IObject, public IRenderable
    {
    public:
        class Face
        {
        public:
            Face() : pMaterial(NULL),p1(NULL),p2(NULL),p3(NULL), pParentMesh(NULL) {};
            unsigned long p1, p2, p3;
            Omen::IMaterial* pMaterial;
            Omen::IMesh*     pParentMesh;
            // Replace the index of corner vertex 
            void replaceVertex( unsigned long p, unsigned long pNew ) { if( p1 == p ) p1 = pNew; else if( p2 == p ) p2 = pNew; else if( p3 == p ) p3 = pNew; }
        };

        class Vertex
        {
        public:
            Vertex() : x(0.0f),y(0.0f),z(0.0f),nx(0.0f),ny(0.0f),nz(0.0f),tu(0.0f),tv(0.0f) { 
                x = ceilf(x*100000)/100000;
                y = ceilf(y*100000)/100000;
                z = ceilf(z*100000)/100000;

                nx = ceilf(nx*100000)/100000;
                ny = ceilf(ny*100000)/100000;
                nz = ceilf(nz*100000)/100000;
            }
            Omen::Float x,y,z;      /// <summary>Vertex coordinates (x,y,z)</summary>
            Omen::Float tu,tv;      /// <summary>Texture cooridnates (tu,tv)</summary>
            Omen::Float nx,ny,nz;   /// <summary>vertex normal direction (x,y,z)</summary>
        };

    public:
        virtual Omen_GUID classId() const = 0;    /// <summary>Defines the class ID</summary>

        virtual void render(const IRenderer* pRenderer) = 0;                    /// <summary>Render this mesh using given renderer</summary>

        // Parenting model
        virtual void setModel( Omen::IModel* pModel ) = 0;
        virtual Omen::IModel* model() const = 0;

        // Scaling
        virtual void scale( Omen::Float& x, Omen::Float& y, Omen::Float& z ) = 0;
        virtual void setScale( Omen::Float x, Omen::Float y, Omen::Float z ) = 0;

        // Vertices
        virtual void addVertex( const Omen::IMesh::Vertex& v ) = 0;
        virtual unsigned long vertexCount() const = 0;
        virtual void getVertices( Omen::IMesh::Vertex* pListVertices, unsigned long& maxSize ) = 0;
        virtual bool getVertex( unsigned long index, std::vector<IMesh::Vertex>::iterator& iter ) = 0;

        // Faces
        virtual void addFace( const Omen::IMesh::Face& face ) = 0;
        virtual void addFace( unsigned long p1, unsigned long p2, unsigned long p3 ) = 0;
        virtual unsigned long faceCount() const = 0;
        virtual void getFaces( Omen::IMesh::Face** pListFaces, unsigned long& maxSize ) = 0;
        virtual bool getFace( unsigned long index, std::vector<IMesh::Face>::iterator& iter ) = 0;

        // Normals
        virtual void updateVertexNormals( Omen::Float limitSmoothAngle = 45.0f ) = 0; /// Calculate the vertex normals and smoothen edeges
        virtual Omen::Vector3d faceNormal( unsigned long faceIndex ) = 0; /// Returns the normal of this face
        virtual Omen::Vector3d faceNormal( const Face& face ) = 0; /// Returns the normal of this face

        // Texture
        virtual void setTexture( Omen::ITexture* pTexture ) = 0;
        virtual Omen::ITexture* texture() const = 0;

        /// Vertex and index buffers
        virtual void setVertexBufferPtr( void* ptrVertexBuffer ) = 0;      /// <summary>Set Renderer specific vertex buffer pointer</summary>
        virtual void setIndexBufferPtr( void* ptrIndexBuffer ) = 0;      /// <summary>Set Renderer specific vertex buffer pointer</summary>

        virtual void* vertexBufferPtr() const = 0;                             /// <summary>Returns the Renderer specific vertex buffer pointer </summary>
        virtual void* indexBufferPtr() const = 0;                              /// <summary>Returns the Renderer specific vertex buffer pointer </summary>

        // Mesh transformation, translation and rotation
        virtual Omen::Matrix4x4 transformation() const = 0;                     /// <summary>Returns the global transformation matrix of the mesh</summary>
        virtual Omen::Vector3d  globalPosition() const = 0;                     /// <summary>Returns the position of the mesh origo in global coordinate space</summary>
        virtual Omen::Vector3d  localPosition() const = 0;                      /// <summary>Returns the position of the mesh in model's/parent's coordinate space</summary>
        virtual Omen::Vector3d center() = 0;                                    /// <summary>Returns the center of this mesh in model's/parent's coordinate space</summary>
        virtual void getRotation( Omen::Float& yaw, Omen::Float& pitch, Omen::Float& roll ) const = 0; /// <summary>Returns the yaw,pitch and roll rotation angles of the mesh</summary>
        virtual void setRotation( Omen::Float yaw, Omen::Float pitch, Omen::Float roll ) = 0; /// <summary>Sets the yaw, pitch and roll rotation angles of the mesh</summary>
        virtual void rotateY( Omen::Float angle ) = 0;                          /// <summary>Rotates the mesh around y-axis for given angle</summary>
        virtual void rotateX( Omen::Float angle ) = 0;                          /// <summary>Rotates the mesh around x-axis for given angle</summary>
        virtual void rotateZ( Omen::Float angle ) = 0;                          /// <summary>Rotates the mesh around z-axis for given angle</summary>
        virtual void translate( const Omen::Vector3d& v ) = 0;                  /// <summary>Translate the position of the mesh by given vector</summary>
        virtual void setPosition( const Omen::Vector3d& v ) = 0;                  /// <summary>Set the position of the mesh to given position</summary>

        // Material
        virtual void setMaterial( Omen::IMaterial* pMaterial ) = 0;
        virtual Omen::IMaterial*  material( unsigned long faceIndex = -1 ) const = 0;

        /// Shaders
        virtual void setVertexShaderPtr( Omen::IShader* ptrVertexShader ) = 0;    /// <summary>Set the vertex shader pointer</summary>
        virtual Omen::IShader* vertexShaderPtr() const = 0;                         /// <summary>Set the vertex shader pointer</summary>

        // Bounding volumes, Sphere and Axis Aligned Bounding Box (AABB) of the mesh
        virtual const Omen::Sphere& boundingSphere() const = 0;
        virtual const Omen::AABB& boundingBox() const = 0;
        virtual void updateBoundingVolumes() = 0;

        virtual void centralizeVertices() = 0;

        virtual bool hasChanged() const = 0;                                      /// boolean value to indicate whether this mesh has changed since last frame
        
    protected:
    private:
    };
}